home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / applic / ntp / depredated / xntp2 / refclock_pst.c.Z / refclock_pst.c
Encoding:
C/C++ Source or Header  |  1991-09-29  |  41.0 KB  |  1,738 lines

  1. /*
  2.  * refclock_pst - driver for the PSTI 1010/1020 WWV clock
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <sys/time.h>
  10. #include <sys/file.h>
  11. #include <sys/ioctl.h>
  12. #include <sgtty.h>
  13.  
  14. #include "ntp_syslog.h"
  15. #include "ntp_fp.h"
  16. #include "ntp.h"
  17. #include "ntp_refclock.h"
  18. #include "ntp_unixtime.h"
  19.  
  20. #if defined(REFCLOCK) && defined(PST)
  21. /*
  22.  * This driver is in good measure due to David Schachter, who wrote
  23.  * the firmware for the PST clock.  Not that he is to blame for
  24.  * any of this, but he kindly loaned me a clock to allow me to
  25.  * debug this.
  26.  *
  27.  * Postscript:
  28.  *
  29.  * The strategy in here is actually pretty good, especially if
  30.  * you try to support the clock on something lacking low order
  31.  * clock bits like a Sun, since all the business which is done
  32.  * before taking a time stamp tends to randomize the taking of
  33.  * the stamp with respect to the timer interrupt.  It is, however,
  34.  * a big cpu hog, and in some ways is a bit of a waste since, as
  35.  * it turns out, the PST clock can give you no better than a
  36.  * millisecond precision and it doesn't pay to try to push it
  37.  * harder.
  38.  *
  39.  * In any event, like the first waffle off the iron, this one
  40.  * should probably be tossed.  My current preference would be
  41.  * to retain the 12-a-minute schedule, but to use the QU command
  42.  * instead of the QD and QT, and to only send a QM command with
  43.  * the 12th poll of the minute to get the minutes-since-sync
  44.  * and the station.  Need to get a clock which supports QU,
  45.  * however.
  46.  *
  47.  * End postscript
  48.  *
  49.  * This driver polls the clock using the QM, QT and QD commands.
  50.  * Ntpd actually uses QU instead of the last two, something I would
  51.  * like to have done as well since it gives you the day and time
  52.  * atom, but the firmware in the clock I had (X04.01.999) didn't know
  53.  * about this command.
  54.  *
  55.  * The QM command produces output like:
  56.  *
  57.  *    O6B532352823C00270322
  58.  *       b     c  deeee
  59.  *
  60.  * We use (b) for the time zone, (c) to see whether time is available,
  61.  * (d) to tell whether we are sync'd to WWV or WWVH, and (e) to determine
  62.  * the number of minutes since the last signal was received.  We
  63.  * don't trust the clock for more than about 20 minutes on its own.
  64.  * After this, we keep taking the time but mark the clock unsynchronized.
  65.  *
  66.  * The QT command returns something that looks like this:
  67.  *
  68.  *    18:57:50.263D
  69.  *
  70.  * Note that this particular sample is in 24 hour format, local time
  71.  * (daylight savings time even).  We allow just about anything for
  72.  * this (sigh) since this leaves the clock owner free to set the
  73.  * display mode in whatever way he finds convenient for setting
  74.  * his watch.
  75.  *
  76.  * The QD command returns:
  77.  *
  78.  *    89/10/19/292
  79.  *
  80.  * We actually only use the day-of-the-year here.  We use the year
  81.  * only to determine whether the PST clock thinks the current year
  82.  * has 365 or 366 days in it.
  83.  *
  84.  * At the current writing, this code expects to be using a BSD-style
  85.  * terminal driver.  It will compile code which uses the CLKLDISC
  86.  * line discipline if it thinks this is available, but use cooked
  87.  * mode otherwise.  The cooked mode stuff may not have been tested.
  88.  */
  89.  
  90. /*
  91.  * Definitions
  92.  */
  93. #define    MAXUNITS    4    /* maximum number of PST units permitted */
  94. #define    PSTDEV    "/dev/pst%d"    /* device we open.  %d is unit number */
  95. #define    NPSTSAMPS    12    /* take 12 PST samples per minute */
  96.  
  97. /*
  98.  * When the PST clock is operating optimally we want the primary clock
  99.  * distance to come out at 300 ms.  Thus, peer.distance in the PST peer
  100.  * structure is set to 290 ms and we compute delays which are at least
  101.  * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
  102.  */
  103. #define    PSTDISTANCE    0x00004a3d
  104. #define    PSTBASEDELAY    0x0000028f
  105.  
  106. /*
  107.  * Other constant stuff
  108.  */
  109. #define    PSTPRECISION    (-9)        /* what the heck */
  110. #define    WWVREFID    "WWV\0"
  111. #define    WWVHREFID    "WWVH"
  112. #define    PSTHSREFID    0x7f7f030a    /* 127.127.3.10 refid for hi strata */
  113.  
  114. /*
  115.  * Parameters for the clock
  116.  */
  117. #define    PSTBAUD        B9600
  118. #ifdef CLKLDISC
  119. #define    PSTMAGIC1    '\r'
  120. #define    PSTMAGIC2    ('\r' | 0x80)
  121. #define    PSTEOL        '\r'
  122. #else
  123. #define    PSTEOL        '\n'
  124. #endif
  125.  
  126. /*
  127.  * Description of clock.  We fill in whether it is a 1010 or 1020,
  128.  * and the firmware revision, using the QV command.
  129.  */
  130. #define    PSTDESCLEN    64
  131. #define    PSTDESCRIPTION    "%s %s (%s) WWV/H Receiver"
  132. #define    PSTDEFDESC    "PSTI/Traconex 10?0 (V??.??) WWV/H Receiver"
  133.  
  134. /*
  135.  * Length of the PST time code.  This must be the length of the output
  136.  * of the QM command, plus QT, plus QD, plus two spaces.  We make it
  137.  * big just on principle.
  138.  */
  139. #define    PSTCODELEN    (128)
  140.  
  141. /*
  142.  * Minimum and maximum lengths
  143.  */
  144. #define    PSTMINQVLEN    (16)
  145. #define    PSTMAXQVLEN    (24)
  146.  
  147. #define    PSTMINQMLEN    (19)
  148. #define    PSTMAXQMLEN    (32)
  149.  
  150. #define    PSTMINQDLEN    (12)
  151. #define    PSTMAXQDLEN    (12)
  152.  
  153. #define    PSTMINQTLEN    (14)
  154. #define    PSTMAXQTLEN    (14)
  155.  
  156. /*
  157.  * It turns out that the QT command does *not* adjust for transmission
  158.  * delays.  Since the QT command returns 15 characters at 9600 baud,
  159.  * the adjustment for this should be 15.6 ms.  We'll default to this,
  160.  * but don't let this stop you from fiddling with the fudge factors
  161.  * to make things come out right
  162.  */
  163. #define    PSTQTFUDGE    0x04000000    /* about 15.6 ms */
  164.  
  165. /*
  166.  * Default propagation delays.  About right for Toronto
  167.  */
  168. #define    DEFWWVPROP    0x01eb851f    /* about 7.5 ms */
  169. #define    DEFWWVHPROP    0x06c8b439    /* about 26.5 ms */
  170.  
  171. /*
  172.  * Maximum propagation delay we believe.  125 ms as an l_fp fraction
  173.  */
  174. #define    PSTMAXPROP    0x20000000
  175.  
  176. /*
  177.  * Default minutes since an update.
  178.  */
  179. #define    DEFMAXFREERUN    (20)
  180.  
  181. /*
  182.  * Hold time after a leap second occurs
  183.  */
  184. #define    PSTLEAPHOLD    (3*60*60)    /* 3 hours */
  185.  
  186. /*
  187.  * Hack to avoid excercising the multiplier.  I have no pride.
  188.  */
  189. #define    MULBY10(x)    (((x)<<3) + ((x)<<1))
  190.  
  191. /*
  192.  * PST unit control structure.
  193.  */
  194. struct pstunit {
  195.     struct peer *peer;        /* associated peer structure */
  196.     struct event psttimer;        /* timeout timer structure */
  197.     struct refclockio pstio;    /* given to the I/O handler */
  198.     l_fp rectimes[NPSTSAMPS];    /* times we received this stuff */
  199.     l_fp reftimes[NPSTSAMPS];    /* times of codes received */
  200.     l_fp lastrec;            /* last receive time */
  201.     l_fp lastref;            /* last reference time */
  202.     char description[PSTDESCLEN];    /* description of clock */
  203.     char lastcode[PSTCODELEN];    /* last code we received */
  204.     u_char lencode;            /* length of the last code */
  205.     u_char nextsample;        /* the next offset expected */
  206.     u_char unit;            /* unit number for this guy */
  207.     u_char state;            /* what we're waiting for */
  208.     s_char station;            /* WWV or WWVH? */
  209.     u_char dontsync;        /* something detected to prevent sync */
  210.     u_char flags;            /* flag byte */
  211.     u_char status;            /* clock status */
  212.     u_char lastevent;        /* last clock event */
  213.     u_char timezone;        /* hour offset to time zone */
  214.     u_char errors;            /* number of errors detected */
  215.     u_char year;            /* year reported by clock */
  216.     u_char month;            /* month, from clock */
  217.     u_char monthday;        /* day, from clock */
  218.     u_char hour;            /* hour of day */
  219.     u_char minute;            /* minute of day */
  220.     u_char second;            /* second of day */
  221.     s_char tzoffset;        /* time zone offset */
  222.     u_char reason;            /* reason for failure */
  223.     u_short millisecond;        /* millisecond of day */
  224.     u_short yearday;        /* day of the year */
  225.     u_short timesincesync;        /* time since radio got sample */
  226.     u_long yearstart;        /* NTP time at year start */
  227.     u_long leapend;            /* time of ending of leap event */
  228.     u_long lastupdate;        /* last time data received */
  229.     u_long polls;            /* number of polls */
  230.     u_long noreply;            /* number of time outs */
  231.     u_long badformat;        /* number of bad format responses */
  232.     u_long baddata;            /* number of invalid time codes */
  233.     u_long timestarted;        /* time we started this */
  234. };
  235.  
  236. /*
  237.  * States we might be in
  238.  */
  239. #define    STATE_IDLE    0        /* not doing anything in particular */
  240. #define    STATE_QV    1        /* trying to get version */
  241. #define    STATE_QM    2        /* sent QM */
  242. #define    STATE_QD    3        /* sent QD */
  243. #define    STATE_QT    4        /* send QT */
  244.  
  245. /*
  246.  * Status flags
  247.  */
  248. #define    PST_LEAPYEAR    0x1        /* pst clock thinks it is a leap year */
  249. #define    PST_SIGFAULT    0x2        /* signal fault */
  250. #define    PST_HARDERR    0x4        /* hardware error */
  251. #define    PST_NOTIME    0x8        /* no time available */
  252. #define    PST_WWVH    0x10        /* synchronized to WWVH */
  253. #define    PST_DOQV    0x20        /* get version, reinit delays */
  254. #define    PST_DORESET    0x40        /* reset the clock */
  255.  
  256. /*
  257.  * The PST often encodes stuff by adding an ASCII '0' to it.  The
  258.  * largest range of values encoded this way is 0 through 31, or '0'
  259.  * through 'O'.  These macroes manipulate these values.
  260.  */
  261. #define    ISVALIDPST(c)    ((c) >= '0' && (c) <= 'O')
  262. #define    PSTTOBIN(c)    ((int)(c) - '0')
  263. #define    BINTOPST(c)    ((char)((c) + '0'))
  264.  
  265. /*
  266.  * Status bits.  Look at the QM command
  267.  */
  268. #define    SIGFAULT    0x1
  269. #define    HARDFAULT    0x2
  270. #define    OUTOFSPEC    0x4
  271. #define    TIMEAVAILABLE    0x8
  272.  
  273. /*
  274.  * Module reason codes
  275.  */
  276. #define    QVREASON    20
  277. #define    QMREASON    40
  278. #define    QDREASON    60
  279. #define    QTREASON    80
  280.  
  281. /*
  282.  * Station i.d. characters in QM output
  283.  */
  284. #define    WWV_CHAR    'C'
  285. #define    WWVH_CHAR    'H'
  286.  
  287. /*
  288.  * We allow a few errors, but if we get more than 12 seconds behind
  289.  * the schedule we start from sample 0 again.  4 seconds is the minimum
  290.  * time between time out routine executions.
  291.  */
  292. #define    PSTMAXDELAY    12
  293. #define    PSTMINTIMEOUT    4
  294.  
  295. /*
  296.  * The PST polling schedule.  We poll 12 times per 64 seconds (far too
  297.  * many, but what the heck).  The polls are scheduled to finish in this
  298.  * time with the assumption that the timer is good for no better than
  299.  * 4 second resolution.  If we get too far behind (due to bad samples
  300.  * or no responses) we start over.
  301.  */
  302. struct pstsched {
  303.     u_short nextinterval;
  304.     u_short tooold;
  305. };
  306.  
  307. static struct pstsched psttab[NPSTSAMPS] = {
  308.     { 4,    PSTMAXDELAY+1 },
  309.     { 4,    PSTMAXDELAY+1+4 },
  310.     { 8,    PSTMAXDELAY+1+4+4 },
  311.     { 4,    PSTMAXDELAY+1+4+4+8 },
  312.     { 8,    PSTMAXDELAY+1+4+4+8+4 },
  313.     { 4,    PSTMAXDELAY+1+4+4+8+4+8 },
  314.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4 },
  315.     { 8,    PSTMAXDELAY+1+4+4+8+4+8+4+4 },
  316.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8 },
  317.     { 8,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4 },
  318.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8 },
  319.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8+4 }
  320. };
  321.  
  322.  
  323. /*
  324.  * Data space for the unit structures.  Note that we allocate these on
  325.  * the fly, but never give them back.
  326.  */
  327. static struct pstunit *pstunits[MAXUNITS];
  328. static u_char unitinuse[MAXUNITS];
  329.  
  330. /*
  331.  * Structure to keep processed propagation data in.
  332.  */
  333. struct pst_propagate {
  334.     u_long remainder;    /* left over submillisecond remainder */
  335.     char msbchar;        /* character for high order bits */
  336.     char lsbchar;        /* character for low order bits */
  337. };
  338.  
  339.  
  340. /*
  341.  * Keep the fudge factors separately so they can be set even
  342.  * when no clock is configured.
  343.  */
  344. static l_fp wwv_prop_delay[MAXUNITS];
  345. static l_fp wwvh_prop_delay[MAXUNITS];
  346. static struct pst_propagate wwv_prop_data[MAXUNITS];
  347. static struct pst_propagate wwvh_prop_data[MAXUNITS];
  348. static u_char stratumtouse[MAXUNITS];
  349. static u_char sloppyclock[MAXUNITS];
  350. static u_short freerun[MAXUNITS];
  351.  
  352. /*
  353.  * Pointer to the default description
  354.  */
  355. static char *pstdefdesc = PSTDEFDESC;
  356.  
  357. /*
  358.  * macro for writing to the clock, printing an error if we fail
  359.  */
  360. #define    pst_send(pst, str, len)        \
  361.     if (write((pst)->pstio.fd, (str), (len)) < 0) \
  362.         pst_write_error((pst))
  363.  
  364. /*
  365.  * macro for resetting the clock structure to zero
  366.  */
  367. #define    pst_reset(pst) \
  368.     do { \
  369.         pst->nextsample = 0; \
  370.         pst->station = 0; \
  371.         pst->dontsync = 0; \
  372.     } while (0)
  373.  
  374. /*
  375.  * macro for event reporting
  376.  */
  377. #define    pst_event(pst, evnt_code) \
  378.     do { \
  379.         if ((pst)->status != (u_char)(evnt_code)) \
  380.             pst_do_event((pst), (evnt_code)); \
  381.     } while (0)
  382.  
  383. /*
  384.  * Imported from the timer module
  385.  */
  386. extern u_long current_time;
  387. extern struct event timerqueue[];
  388.  
  389. /*
  390.  * Time conversion tables imported from the library
  391.  */
  392. extern u_long msutotsflo[];
  393. extern u_long msutotsfhi[];
  394.  
  395.  
  396. /*
  397.  * pst_init - initialize internal PST driver data
  398.  */
  399. void
  400. pst_init()
  401. {
  402.     register int i;
  403.     void pst_compute_delay();
  404.  
  405.     /*
  406.      * Just zero the data arrays
  407.      */
  408.     bzero((char *)pstunits, sizeof pstunits);
  409.     bzero((char *)unitinuse, sizeof unitinuse);
  410.  
  411.     /*
  412.      * Initialize fudge factors to default.
  413.      */
  414.     for (i = 0; i < MAXUNITS; i++) {
  415.         wwv_prop_delay[i].l_ui = 0;
  416.         wwv_prop_delay[i].l_uf = DEFWWVPROP;
  417.         pst_compute_delay(DEFWWVPROP, &wwv_prop_data[i]);
  418.         wwvh_prop_delay[i].l_ui = 0;
  419.         wwvh_prop_delay[i].l_uf = DEFWWVHPROP;
  420.         pst_compute_delay(DEFWWVHPROP, &wwvh_prop_data[i]);
  421.         stratumtouse[i] = 0;
  422.         sloppyclock[i] = 0;
  423.         freerun[i] = DEFMAXFREERUN;
  424.     }
  425. }
  426.  
  427.  
  428. /*
  429.  * pst_start - open the PST device and initialize data for processing
  430.  */
  431. int
  432. pst_start(unit, peer)
  433.     u_int unit;
  434.     struct peer *peer;
  435. {
  436.     register struct pstunit *pst;
  437.     register int i;
  438.     int fd;
  439.     int ldisc;
  440.     char pstdev[20];
  441.     struct sgttyb ttyb;
  442.     void pst_timeout();
  443.     void pst_receive();
  444.     extern int io_addclock();
  445.     extern char *emalloc();
  446.  
  447.     if (unit >= MAXUNITS) {
  448.         syslog(LOG_ERR, "pst clock: unit number %d invalid (max %d)",
  449.             unit, MAXUNITS-1);
  450.         return 0;
  451.     }
  452.     if (unitinuse[unit]) {
  453.         syslog(LOG_ERR, "pst clock: unit number %d in use", unit);
  454.         return 0;
  455.     }
  456.  
  457.     /*
  458.      * Unit okay, attempt to open the device.
  459.      */
  460.     (void) sprintf(pstdev, PSTDEV, unit);
  461.  
  462.     fd = open(pstdev, O_RDWR, 0777);
  463.     if (fd == -1) {
  464.         syslog(LOG_ERR, "pst clock: open of %s failed: %m", pstdev);
  465.         return 0;
  466.     }
  467.  
  468.     /*
  469.      * Set for exclusive use
  470.      */
  471.     if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
  472.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCEXCL): %m", pstdev);
  473.         (void) close(fd);
  474.         return 0;
  475.     }
  476.  
  477.     /*
  478.      * Set to raw mode
  479.      */
  480.     ttyb.sg_ispeed = ttyb.sg_ospeed = PSTBAUD;
  481. #ifdef CLKLDISC
  482.     ttyb.sg_erase = PSTMAGIC1;
  483.     ttyb.sg_kill = PSTMAGIC2;
  484.     ttyb.sg_flags = EVENP|ODDP|RAW|CRMOD;
  485. #else
  486.     ttyb.sg_erase = ttyb.sg_kill = 0;
  487.     ttyb.sg_flags = EVENP|ODDP|CRMOD;
  488. #endif
  489.     if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
  490.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCSETP): %m", pstdev);
  491.         return 0;
  492.     }
  493.  
  494.     /*
  495.      * Looks like this might succeed.  Find memory for the structure.
  496.      * Look to see if there are any unused ones, if not we malloc()
  497.      * one.
  498.      */
  499.     if (pstunits[unit] != 0) {
  500.         pst = pstunits[unit];    /* The one we want is okay */
  501.     } else {
  502.         for (i = 0; i < MAXUNITS; i++) {
  503.             if (!unitinuse[i] && pstunits[i] != 0)
  504.                 break;
  505.         }
  506.         if (i < MAXUNITS) {
  507.             /*
  508.              * Reclaim this one
  509.              */
  510.             pst = pstunits[i];
  511.             pstunits[i] = 0;
  512.         } else {
  513.             pst = (struct pstunit *)emalloc(sizeof(struct pstunit));
  514.         }
  515.     }
  516.     bzero((char *)pst, sizeof(struct pstunit));
  517.     pstunits[unit] = pst;
  518.  
  519.     /*
  520.      * Set up the structure
  521.      */
  522.     pst->peer = peer;
  523.     pst->unit = (u_char)unit;
  524.     pst->state = STATE_IDLE;
  525.     pst->flags |= PST_DOQV;
  526.     pst->timestarted = current_time;
  527.     (void) strcpy(pst->description, pstdefdesc);
  528.  
  529.     pst->psttimer.peer = (struct peer *)pst;
  530.     pst->psttimer.event_handler = pst_timeout;
  531.  
  532.     pst->pstio.clock_recv = pst_receive;
  533.     pst->pstio.srcclock = (caddr_t)pst;
  534.     pst->pstio.datalen = 0;
  535.     pst->pstio.fd = fd;
  536.  
  537.     /*
  538.      * Okay.  Set the line discipline to the clock line discipline,
  539.      * if we have it, then give it to the I/O code to start receiving
  540.      * stuff.
  541.      */
  542. #ifdef CLKLDISC
  543.     ldisc = CLKLDISC;
  544.     if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
  545.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCSETD): %m", pstdev);
  546.         (void) close(fd);
  547.         return 0;
  548.     }
  549. #else
  550.     ldisc = 0;
  551.     if (ioctl(fd, TIOCFLUSH, (char *)&ldisc) < 0) {
  552.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCFLUSH): %m", pstdev);
  553.         (void) close(fd);
  554.         return 0;
  555.     }
  556. #endif
  557.     if (!io_addclock(&pst->pstio)) {
  558.         /*
  559.          * Oh shit.  Just close and return.
  560.          */
  561.         (void) close(fd);
  562.         return 0;
  563.     }
  564.  
  565.     /*
  566.      * All done.  Initialize a few random peer variables, then
  567.      * start the timer and return success.
  568.      */
  569.     peer->distance = PSTDISTANCE;
  570.     peer->precision = PSTPRECISION;
  571.     peer->stratum = stratumtouse[unit];
  572.     if (stratumtouse[unit] <= 1)
  573.         bcopy(WWVREFID, (char *)&peer->refid, 4);
  574.     else
  575.         peer->refid = htonl(PSTHSREFID);
  576.     pst->psttimer.event_time = current_time + PSTMINTIMEOUT;
  577.     TIMER_ENQUEUE(timerqueue, &pst->psttimer);
  578.     unitinuse[unit] = 1;
  579.     return 1;
  580. }
  581.  
  582.  
  583. /*
  584.  * pst_shutdown - shut down a PST clock
  585.  */
  586. void
  587. pst_shutdown(unit)
  588.     int unit;
  589. {
  590.     register struct pstunit *pst;
  591.     extern void io_closeclock();
  592.  
  593.     if (unit >= MAXUNITS) {
  594.         syslog(LOG_ERR,
  595.           "pst clock: INTERNAL ERROR, unit number %d invalid (max %d)",
  596.             unit, MAXUNITS-1);
  597.         return;
  598.     }
  599.     if (!unitinuse[unit]) {
  600.         syslog(LOG_ERR,
  601.          "pst clock: INTERNAL ERROR, unit number %d not in use", unit);
  602.         return;
  603.     }
  604.  
  605.     /*
  606.      * Tell the I/O module to turn us off, and dequeue timer
  607.      * if any.  We're history.
  608.      */
  609.     pst = pstunits[unit];
  610.     TIMER_DEQUEUE(&pst->psttimer);
  611.     io_closeclock(&pst->pstio);
  612.     unitinuse[unit] = 0;
  613. }
  614.  
  615.  
  616. /*
  617.  * pst_write_error - complain about writes to the clock
  618.  */
  619. static void
  620. pst_write_error(pst)
  621.     struct pstunit *pst;
  622. {
  623.     /*
  624.      * This will fill syslog is something is really wrong.  Should
  625.      * throttle it back.
  626.      */
  627.     syslog(LOG_ERR, "pst clock: write error on unit %d: %m",
  628.         pst->unit);
  629. }
  630.  
  631.  
  632. /*
  633.  * pst_timeout - process a timeout event
  634.  */
  635. void
  636. pst_timeout(fakepeer)
  637.     struct peer *fakepeer;
  638. {
  639.     register struct pstunit *pst;
  640.     u_long poll;
  641.  
  642.     /*
  643.      * The timeout routine always initiates a chain of
  644.      * query-responses from the clock, by sending either
  645.      * a QV command (if we need to (re)set the propagation
  646.      * delays into the clock), a QM command or an SRY
  647.      * command (after a leap second).  The pst_receive()
  648.      * routine should complete the set of queries on its own
  649.      * long before the next time out is due, so if we see any
  650.      * state in here other than idle it means the clock hasn't
  651.      * responded.
  652.      */
  653.     pst = (struct pstunit *)fakepeer;
  654.     switch(pst->state) {
  655.     case STATE_IDLE:
  656.         poll = (u_long)psttab[pst->nextsample].nextinterval;
  657.         break;                /* all is well */
  658.  
  659.     case STATE_QV:
  660.         pst->flags |= PST_DOQV;        /* no response, do QV again */
  661.         /*FALLSTHROUGH*/
  662.  
  663.     case STATE_QM:
  664.     case STATE_QD:
  665.     case STATE_QT:
  666.         pst->noreply++;            /* mark the lack of response */
  667.         poll = PSTMINTIMEOUT;        /* minimum time poll */
  668.         break;
  669.  
  670.     default:
  671.         syslog(LOG_ERR,
  672.             "pst clock: INTERNAL ERROR unit %d invalid state %d",
  673.             pst->unit, pst->state);
  674.         poll = PSTMINTIMEOUT;        /* minimum time poll */
  675.         break;
  676.     }
  677.  
  678.     if (pst->flags & PST_DORESET) {
  679.         /*
  680.          * Do a reset.  At the next interrupt, start with
  681.          * a QV command to set in the delays.
  682.          */
  683.         pst->flags &= ~PST_DORESET;
  684.         pst->flags |= PST_DOQV;
  685.         pst->state = STATE_IDLE;
  686.         pst_send(pst, "\003SRY", 4);
  687.     } else if (pst->flags & PST_DOQV) {
  688.         pst->polls++;
  689.         pst->flags &= ~PST_DOQV;
  690.         pst->state = STATE_QV;
  691.         pst_send(pst, "\003QV", 3);
  692.     } else {
  693.         pst->polls++;
  694.         pst->state = STATE_QM;
  695.         pst_send(pst, "\003QM", 3);
  696.     }
  697.  
  698.     pst->psttimer.event_time += poll;
  699.     TIMER_ENQUEUE(timerqueue, &pst->psttimer);
  700. }
  701.  
  702.  
  703. /*
  704.  * pst_QV_process - decode the results of a QV poll and insert fudge
  705.  *            factors into the clock.
  706.  */
  707. static int
  708. pst_QV_process(pst, rbufp)
  709.     register struct pstunit *pst;
  710.     struct recvbuf *rbufp;
  711. {
  712.     register char *cp;
  713.     register char *bp;
  714.     register int len;
  715.     char *model;
  716.     char *company;
  717.     char buf[20];
  718.     static char wwvdelay[6] = { 'S', 'C', '\0', 'S', 'E', '\0' };
  719.     static char wwvhdelay[6] = { 'S', 'H', '\0', 'S', 'G', '\0' };
  720.  
  721.     /*
  722.      * The output of the QV command looks like:
  723.      *
  724.      * PSTI ITS V04.01.000\r
  725.      *
  726.      * or
  727.      *
  728.      * TRAC ITS V04.01.000\r
  729.      *
  730.      * The minimum length of the string is about 16 characters.
  731.      * The maximum length is sort of unbounded, but we get suspicious
  732.      * if it is more than 34.
  733.      */
  734.     len = rbufp->recv_length;
  735.     if (len > PSTMAXQVLEN + 10)
  736.         len = PSTMAXQVLEN + 10;
  737.     
  738.     bp = rbufp->recv_buffer;
  739.     cp = pst->lastcode;
  740.     while (len-- > 0) {
  741.         *cp = (*bp++) & 0x7f;    /* strip parity */
  742.         if (!isprint(*cp))
  743.             break;
  744.         cp++;
  745.     }
  746.     pst->lencode = (u_char)(cp - pst->lastcode);
  747.  
  748.     /*
  749.      * Okay, got all printable characters from the string
  750.      * copied.  We expect to have been terminated by the
  751.      * EOL character.  If not, forget it.  If the length
  752.      * is insane, forget it.
  753.      */
  754.     if (len < 0 || *cp != PSTEOL
  755.         || pst->lencode < PSTMINQVLEN || pst->lencode > PSTMAXQVLEN) {
  756.         pst->reason = QVREASON + 1;
  757.         return 0;
  758.     }
  759.  
  760.     /*
  761.      * Now, format check what we can.  Dump it at the least
  762.      * sign of trouble.
  763.      */
  764.     cp = pst->lastcode;
  765.     if (*cp++ != 'P' || *cp++ != 'S' || *cp++ != 'T'
  766.         || *cp++ != 'I' || *cp++ != ' ') {
  767.         cp = pst->lastcode;
  768.         if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A'
  769.             || *cp++ != 'C' || *cp++ != ' ') {
  770.             pst->reason = QVREASON + 2;
  771.             return 0;
  772.         }
  773.         company = "Traconex";
  774.     } else {
  775.         company = "Precision Standard Time";
  776.     }
  777.  
  778.     if (*cp == 'M')
  779.         model = "1010";
  780.     else if (*cp == 'I')
  781.         model = "1020";
  782.     else {
  783.         pst->reason = QVREASON + 3;
  784.         return 0;
  785.     }
  786.     cp++;
  787.  
  788.     if (*cp++ != 'T' || *cp++ != 'S' || *cp++ != ' ') {
  789.         pst->reason = QVREASON + 4;
  790.         return 0;
  791.     }
  792.     if (*cp != 'X' && *cp != 'V') {
  793.         pst->reason = QVREASON + 5;
  794.         return 0;
  795.     }
  796.     
  797.     /*
  798.      * Next is the version.  Copy it into the buffer.
  799.      */
  800.     bp = buf;
  801.     *bp++ = *cp++;
  802.     while (isdigit(*cp) || *cp == '.')
  803.         *bp++ = *cp++;
  804.     *bp++ = '\0';
  805.  
  806.     /*
  807.      * Final bit of fluff is to set the description
  808.      */
  809.     (void) sprintf(pst->description, PSTDESCRIPTION, company, model, buf);
  810.  
  811.     /*
  812.      * Now the serious stuff.  Since we are now sure that the
  813.      * clock is there, we can be fairly sure that the delay
  814.      * setting commands will take.  Send them.
  815.      */
  816.     wwvdelay[2] = wwv_prop_data[pst->unit].msbchar;
  817.     wwvdelay[5] = wwv_prop_data[pst->unit].lsbchar;
  818.     pst_send(pst, wwvdelay, 6);
  819.  
  820.     /*
  821.      * Same thing for WWVH
  822.      */
  823.     wwvhdelay[2] = wwvh_prop_data[pst->unit].msbchar;
  824.     wwvhdelay[5] = wwvh_prop_data[pst->unit].lsbchar;
  825.     pst_send(pst, wwvhdelay, 6);
  826.  
  827.     /*
  828.      * Should be okay.  Return positive response.
  829.      */
  830.     return 1;
  831. }
  832.  
  833.  
  834. /*
  835.  * pst_QM_process - process the output of a QM command
  836.  */
  837. static int
  838. pst_QM_process(pst, rbufp)
  839.     register struct pstunit *pst;
  840.     struct recvbuf *rbufp;
  841. {
  842.     register char *cp;
  843.     register char *bp;
  844.     register int n;
  845.  
  846.     /*
  847.      * The output of the QM command looks like:
  848.      *
  849.       * O6B532352823C00270322
  850.      *
  851.      * The minimum length of the string is 19 characters.
  852.      * The maximum length is sort of unbounded, but we get suspicious
  853.      * if it is more than 42.
  854.      */
  855.     n = rbufp->recv_length;
  856.     if (n > PSTMAXQMLEN + 10)
  857.         n = PSTMAXQMLEN + 10;
  858.     
  859.     bp = rbufp->recv_buffer;
  860.     cp = pst->lastcode;
  861.     while (n-- > 0) {
  862.         *cp = (*bp++) & 0x7f;    /* strip parity */
  863.         if (!isprint(*cp))
  864.             break;
  865.         cp++;
  866.     }
  867.     pst->lencode = (u_char)(cp - pst->lastcode);
  868.  
  869.     /*
  870.      * Okay, got all printable characters from the string
  871.      * copied.  We expect to have been terminated by the
  872.      * EOL character.  If not, forget it.  If the length
  873.      * is insane, forget it.
  874.      */
  875.     if (n < 0 || *cp != PSTEOL
  876.         || pst->lencode < PSTMINQMLEN || pst->lencode > PSTMAXQMLEN) {
  877.         pst->reason = QMREASON + 1;
  878.         return 0;
  879.     }
  880.  
  881.     /*
  882.      * Ensure that the first PSTMINQMLEN characters are valid with
  883.      * respect to the way the clock encodes binary data.
  884.      */
  885.     cp = pst->lastcode;
  886.     n = pst->lencode;
  887.     while (n-- > 0) {
  888.         if (!ISVALIDPST(*cp)) {
  889.             pst->reason = QMREASON + 2;
  890.             return 0;
  891.         }
  892.         cp++;
  893.     }
  894.  
  895.     /*
  896.      * Collect information we are interested in.
  897.      */
  898.     cp = pst->lastcode;
  899.     pst->timezone = PSTTOBIN(cp[3]);
  900.     if (pst->timezone > 23) {
  901.         pst->reason = QMREASON + 3;
  902.         return 0;
  903.     }
  904.  
  905.     pst->flags &=
  906.         ~(PST_LEAPYEAR|PST_SIGFAULT|PST_HARDERR|PST_NOTIME|PST_WWVH);
  907.     n = PSTTOBIN(cp[4]);
  908.     if (n > 15) {
  909.         pst->reason = QMREASON + 4;
  910.         return 0;
  911.     }
  912.     if (((n + 2) & 0x3) == 0)
  913.         pst->flags |= PST_LEAPYEAR;
  914.  
  915.     n = PSTTOBIN(cp[9]);
  916.     if (n > 15) {
  917.         pst->reason = QMREASON + 5;
  918.         return 0;
  919.     }
  920.     if (n & SIGFAULT)
  921.         pst->flags |= PST_SIGFAULT;
  922.     if (n & HARDFAULT)
  923.         pst->flags |= PST_HARDERR;
  924.     if (!(n & TIMEAVAILABLE))
  925.         pst->flags |= PST_NOTIME;
  926.  
  927.     if (cp[12] == 'H') {
  928.         pst->flags |= PST_WWVH;
  929.     } else if (cp[12] == 'C') {
  930.         pst->flags &= ~PST_WWVH;
  931.     } else {
  932.         pst->reason = QMREASON + 6;
  933.         return 0;
  934.     }
  935.  
  936.     if (wwv_prop_data[pst->unit].msbchar != cp[5] ||
  937.         wwv_prop_data[pst->unit].lsbchar != cp[6] ||
  938.         wwvh_prop_data[pst->unit].msbchar != cp[7] ||
  939.         wwvh_prop_data[pst->unit].lsbchar != cp[8])
  940.         pst->flags |= PST_DOQV;
  941.  
  942.     bp = cp + 13;
  943.     pst->timesincesync = 0;
  944.     while (bp < (cp + 17)) {
  945.         if (!isdigit(*bp)) {
  946.             pst->reason = QMREASON + 6;
  947.             return 0;
  948.         }
  949.         pst->timesincesync = MULBY10(pst->timesincesync)
  950.             + PSTTOBIN(*bp);
  951.         bp++;
  952.     }
  953.  
  954.     /*
  955.      * That's about all we can do.  Return success.
  956.      */
  957.     return 1;
  958. }
  959.  
  960.  
  961. /*
  962.  * pst_QD_process - process the output of a QD command
  963.  */
  964. static int
  965. pst_QD_process(pst, rbufp)
  966.     register struct pstunit *pst;
  967.     struct recvbuf *rbufp;
  968. {
  969.     register char *cp;
  970.     register char *bp;
  971.     register int n;
  972.     char *cpstart;
  973.     int len;
  974.  
  975.     /*
  976.      * The output of the QM command looks like:
  977.      *
  978.       * 88/05/17/138\r
  979.      *
  980.      * The minimum length of the string is 12 characters as is
  981.      * the maximum length.
  982.      */
  983.     n = rbufp->recv_length;
  984.     if (n > PSTMAXQDLEN + 10)
  985.         n = PSTMAXQDLEN + 10;
  986.     
  987.     bp = rbufp->recv_buffer;
  988.     cp = &pst->lastcode[pst->lencode];
  989.     *cp++ = ' ';
  990.     cpstart = cp;
  991.     while (n-- > 0) {
  992.         *cp = (*bp++) & 0x7f;    /* strip parity */
  993.         if (!isprint(*cp))
  994.             break;
  995.         cp++;
  996.     }
  997.     len = (cp - cpstart);
  998.     pst->lencode = (u_char)(cp - pst->lastcode);
  999.  
  1000.     /*
  1001.      * Okay, got all printable characters from the string
  1002.      * copied.  We expect to have been terminated by the
  1003.      * EOL character.  If not, forget it.  If the length
  1004.      * is insane, forget it.
  1005.      */
  1006.     if (n < 0 || *cp != PSTEOL ||
  1007.         len < PSTMINQDLEN || len > PSTMAXQDLEN) {
  1008.         pst->reason = QDREASON + 1;
  1009.         return 0;
  1010.     }
  1011.  
  1012.     /*
  1013.      * Ensure that the characters are formatted validly.  They
  1014.      * are either digits or '/'s.
  1015.      */
  1016.     cp = cpstart;
  1017.     if (!isdigit(cp[0]) || !isdigit(cp[1]) || cp[2] != '/' ||
  1018.         !isdigit(cp[3]) || !isdigit(cp[4]) || cp[5] != '/' ||
  1019.         !isdigit(cp[6]) || !isdigit(cp[7]) || cp[8] != '/' ||
  1020.         !isdigit(cp[9]) || !isdigit(cp[10]) || !isdigit(cp[11])) {
  1021.         pst->reason = QDREASON + 2;
  1022.         return 0;
  1023.     }
  1024.  
  1025.     /*
  1026.      * Decode into year, month, day and year day
  1027.      */
  1028.     pst->year = MULBY10(PSTTOBIN(cp[0])) + PSTTOBIN(cp[1]);
  1029.     pst->month = MULBY10(PSTTOBIN(cp[3])) + PSTTOBIN(cp[4]);
  1030.     pst->monthday = MULBY10(PSTTOBIN(cp[6])) + PSTTOBIN(cp[7]);
  1031.     pst->yearday = MULBY10(PSTTOBIN(cp[9])) + PSTTOBIN(cp[10]);
  1032.     pst->yearday = MULBY10(pst->yearday) + PSTTOBIN(cp[11]);
  1033.  
  1034.     /*
  1035.      * Format check these.
  1036.      */
  1037.     if (pst->month > 12 || pst->monthday > 31 || pst->yearday > 366) {
  1038.         pst->reason = QDREASON + 3;
  1039.         return 0;
  1040.     }
  1041.     if (!(pst->flags & PST_LEAPYEAR) && pst->yearday > 365) {
  1042.         pst->reason = QDREASON + 4;
  1043.         return 0;
  1044.     }
  1045.  
  1046.     /*
  1047.      * Done all we can.
  1048.      */
  1049.     return 1;
  1050. }
  1051.  
  1052.  
  1053. /*
  1054.  * pst_QT_process - process the output of a QT command, return the times
  1055.  */
  1056. static int
  1057. pst_QT_process(pst, rbufp, tsclk, tsrec)
  1058.     register struct pstunit *pst;
  1059.     struct recvbuf *rbufp;
  1060.     l_fp *tsclk;
  1061.     l_fp *tsrec;
  1062. {
  1063.     register char *cp;
  1064.     register char *bp;
  1065.     register int n;
  1066.     char *cpstart;
  1067.     int len;
  1068.     int hour;
  1069.     int minute;
  1070.     int second;
  1071.     int msec;
  1072.     int tzoff;
  1073.     extern int buftvtots();
  1074.  
  1075.     /*
  1076.      * The output of the QT command looks like:
  1077.      *
  1078.       * A09:57:50.263D
  1079.       * 
  1080.      * The minimum length of the string is 14 characters as is
  1081.      * the maximum length.
  1082.      */
  1083.     n = rbufp->recv_length;
  1084.     if (n > PSTMAXQTLEN + 10)
  1085.         n = PSTMAXQTLEN + 10;
  1086.     
  1087.     bp = rbufp->recv_buffer;
  1088.     cp = &pst->lastcode[pst->lencode];
  1089.     *cp++ = ' ';
  1090.     cpstart = cp;
  1091.     while (n-- > 0) {
  1092.         *cp = (*bp++) & 0x7f;    /* strip parity */
  1093.         if (!isprint(*cp))
  1094.             break;
  1095.         cp++;
  1096.     }
  1097.     len = (cp - cpstart);
  1098.     pst->lencode = (u_char)(cp - pst->lastcode);
  1099.  
  1100.     /*
  1101.      * Okay, got all printable characters from the string
  1102.      * copied.  We expect to have been terminated by the
  1103.      * EOL character.  If not, forget it.  If the length
  1104.      * is insane, forget it.
  1105.      */
  1106.     if (n < 0 || *cp != PSTEOL ||
  1107.         len < PSTMINQTLEN || len > PSTMAXQTLEN) {
  1108.         pst->reason = QTREASON + 1;
  1109.         return 0;
  1110.     }
  1111. #ifdef CLKLDISC
  1112.     /*
  1113.      * Receive time stamp should be in buffer after the code.
  1114.      * Make sure we have enough characters in there.
  1115.      */
  1116.     if (&rbufp->recv_buffer[rbufp->recv_length] - bp < 8) {
  1117.         pst->reason = QTREASON + 2;
  1118.         return 0;
  1119.     }
  1120.     if (!buftvtots(bp, tsrec)) {
  1121.         pst->reason = QTREASON + 3;
  1122.         return 0;
  1123.     }
  1124. #else
  1125.     /*
  1126.      * Use the timestamp collected with the input.
  1127.      */
  1128.     *tsrec = rbufp->recv_time;
  1129. #endif
  1130.  
  1131.     /*
  1132.      * Ensure that the characters are formatted validly.  Mostly
  1133.      * digits, but the occasional `:' and `.'.
  1134.      */
  1135.     cp = cpstart;
  1136.     if (!isdigit(cp[1]) || !isdigit(cp[2]) || cp[3] != ':' ||
  1137.         !isdigit(cp[4]) || !isdigit(cp[5]) || cp[6] != ':' ||
  1138.         !isdigit(cp[7]) || !isdigit(cp[8]) || cp[9] != '.' ||
  1139.         !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[12])) {
  1140.         pst->reason = QTREASON + 4;
  1141.         return 0;
  1142.     }
  1143.  
  1144.     /*
  1145.      * Extract the hour, minute, second and millisecond
  1146.      */
  1147.     hour = MULBY10(PSTTOBIN(cp[1])) + PSTTOBIN(cp[2]);
  1148.     minute = MULBY10(PSTTOBIN(cp[4])) + PSTTOBIN(cp[5]);
  1149.     second = MULBY10(PSTTOBIN(cp[7])) + PSTTOBIN(cp[8]);
  1150.     msec = MULBY10(PSTTOBIN(cp[10])) + PSTTOBIN(cp[11]);
  1151.     msec = MULBY10(msec) + PSTTOBIN(cp[12]);
  1152.  
  1153.     if (minute > 59 || second > 59) {
  1154.         pst->reason = QTREASON + 5;
  1155.         return 0;
  1156.     }
  1157.  
  1158.     /*
  1159.      * Trouble here.  Adjust the hours for AM/PM, if this is
  1160.      * on, and for daylight saving time.
  1161.      */
  1162.     if (*cp == 'A') {
  1163.         if (hour > 12 || hour == 0) {
  1164.             pst->reason = QTREASON + 5;
  1165.             return 0;
  1166.         }
  1167.         if (hour == 12)
  1168.             hour = 0;
  1169.     } else if (*cp == 'P') {
  1170.         if (hour > 12 || hour == 0)
  1171.             return 0;
  1172.         if (hour < 12)
  1173.             hour += 12;
  1174.     } else if (*cp != ' ') {
  1175.         pst->reason = QTREASON + 6;
  1176.         return 0;
  1177.     }
  1178.  
  1179.     if (cp[13] == 'D')
  1180.         tzoff = -1;
  1181.     else if (cp[13] == ' ')
  1182.         tzoff = 0;
  1183.     else {
  1184.         pst->reason = QTREASON + 7;
  1185.         return 0;
  1186.     }
  1187.  
  1188.     /*
  1189.      * Adjust for the timezone.  The PST manual is screwy here.
  1190.      * it says the timezone is an integer in the range 0 to 23,
  1191.      * but this doesn't allow us to tell the difference between
  1192.      * +12 and -12.  Assume the 12 hour timezone is west of
  1193.      * GMT.
  1194.      */
  1195.     if (pst->timezone <= 12)
  1196.         tzoff += pst->timezone;
  1197.     else
  1198.         tzoff -= (24 - pst->timezone);
  1199.  
  1200.  
  1201.     /*
  1202.      * Record for posterity
  1203.      */
  1204.     pst->hour = (u_char)hour;
  1205.     pst->minute = (u_char)minute;
  1206.     pst->second = (u_char)second;
  1207.     pst->millisecond = (u_short)msec;
  1208.     pst->tzoffset = (s_char)tzoff;
  1209.  
  1210.     /*
  1211.      * All that to get the day-hour-minute-second.  Turn this
  1212.      * into the seconds part of a time stamp.  Also use the
  1213.      * milliseconds part directly as the fractional part.
  1214.      */
  1215.     MSUTOTSF(msec, tsclk->l_uf);
  1216.     if (!clocktime((int)pst->yearday, hour, minute, second, tzoff,
  1217.         tsrec->l_ui, &pst->yearstart, &tsclk->l_ui)) {
  1218.         pst->reason = QTREASON + 8;
  1219.         return 0;
  1220.     }
  1221.  
  1222.     /*
  1223.      * Add in the fudge
  1224.      */
  1225.     if (pst->flags & PST_WWVH)
  1226.         L_ADDUF(tsclk, wwvh_prop_data[pst->unit].remainder);
  1227.     else
  1228.         L_ADDUF(tsclk, wwv_prop_data[pst->unit].remainder);
  1229.  
  1230.     /*
  1231.      * Glad that's over with
  1232.      */
  1233.     return 1;
  1234. }
  1235.  
  1236.  
  1237. /*
  1238.  * pst_do_event - update our status and report any changes
  1239.  */
  1240. static void
  1241. pst_do_event(pst, evnt_code)
  1242.     register struct pstunit *pst;
  1243.     int evnt_code;
  1244. {
  1245.     if (pst->status != (u_char)evnt_code) {
  1246.         pst->status = (u_char)evnt_code;
  1247.         if (evnt_code != CEVNT_NOMINAL)
  1248.             pst->lastevent = (u_char)evnt_code;
  1249.         /*
  1250.          * Should trap this, but the trap code isn't up to
  1251.          * it yet.
  1252.          */
  1253.     }
  1254. }
  1255.  
  1256.  
  1257.  
  1258. /*
  1259.  * pst_process - process the data collected to produce an offset estimate
  1260.  */
  1261. static void
  1262. pst_process(pst)
  1263.     register struct pstunit *pst;
  1264. {
  1265.     register int i;
  1266.     register int n;
  1267.     register u_long tmp_ui;
  1268.     register u_long tmp_uf;
  1269.     register u_long date_ui;
  1270.     register u_long date_uf;
  1271.     u_fp delay;
  1272.     l_fp off[NPSTSAMPS];
  1273.     extern void refclock_receive();
  1274.  
  1275.     /*
  1276.      * Compute offsets from the raw data.  Sort them into
  1277.      * ascending order.
  1278.      */
  1279.     for (i = 0; i < NPSTSAMPS; i++) {
  1280.         tmp_ui = pst->reftimes[i].l_ui;
  1281.         tmp_uf = pst->reftimes[i].l_uf;
  1282.         M_SUB(tmp_ui, tmp_uf, pst->rectimes[i].l_ui,
  1283.             pst->rectimes[i].l_uf);
  1284.         for (n = i; n > 0; n--) {
  1285.             if (M_ISGEQ(tmp_ui, tmp_uf, off[n-1].l_ui,
  1286.                 off[n-1].l_uf))
  1287.                 break;
  1288.             off[n] = off[n-1];
  1289.         }
  1290.         off[n].l_ui = tmp_ui;
  1291.         off[n].l_uf = tmp_uf;
  1292.     }
  1293.  
  1294.     /*
  1295.      * Reject the furthest from the median until 8 samples left
  1296.      */
  1297.     i = 0;
  1298.     n = NPSTSAMPS;
  1299.     while ((n - i) > 8) {
  1300.         tmp_ui = off[n-1].l_ui;
  1301.         tmp_uf = off[n-1].l_uf;
  1302.         date_ui = off[(n+i)/2].l_ui;
  1303.         date_uf = off[(n+i)/2].l_uf;
  1304.         M_SUB(tmp_ui, tmp_uf, date_ui, date_uf);
  1305.         M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf);
  1306.         if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) {
  1307.             /*
  1308.              * reject low end
  1309.              */
  1310.             i++;
  1311.         } else {
  1312.             /*
  1313.              * reject high end
  1314.              */
  1315.             n--;
  1316.         }
  1317.     }
  1318.  
  1319.     /*
  1320.      * Compute the delay based on the difference between the
  1321.      * extremes of the remaining offsets.
  1322.      */
  1323.     tmp_ui = off[n-1].l_ui;
  1324.     tmp_uf = off[n-1].l_uf;
  1325.     M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
  1326.     delay = PSTBASEDELAY + MFPTOFP(tmp_ui, tmp_uf);
  1327.  
  1328.     /*
  1329.      * Now compute the offset estimate.  If the sloppy clock
  1330.      * flag is set, average the remainder, otherwise pick the
  1331.      * median.
  1332.      */
  1333.     if (sloppyclock[pst->unit]) {
  1334.         tmp_ui = tmp_uf = 0;
  1335.         while (i < n) {
  1336.             M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
  1337.             i++;
  1338.         }
  1339.         M_RSHIFT(tmp_ui, tmp_uf);
  1340.         M_RSHIFT(tmp_ui, tmp_uf);
  1341.         M_RSHIFT(tmp_ui, tmp_uf);
  1342.         i = 0;
  1343.         off[0].l_ui = tmp_ui;
  1344.         off[0].l_uf = tmp_uf;
  1345.     } else {
  1346.         i = (n+i)/2;
  1347.     }
  1348.  
  1349.     /*
  1350.      * Add the default PST QT delay into this.
  1351.      */
  1352.     L_ADDUF(&off[i], PSTQTFUDGE);
  1353.  
  1354.     /*
  1355.      * Set the reference ID to the appropriate station
  1356.      */
  1357.     if (stratumtouse[pst->unit] <= 1) {
  1358.         if (pst->station >= 0)
  1359.             bcopy(WWVREFID, (char *)&pst->peer->refid, 4);
  1360.         else
  1361.             bcopy(WWVHREFID, (char *)&pst->peer->refid, 4);
  1362.     }
  1363.  
  1364.     /*
  1365.      * Give the data to the reference clock support code
  1366.      */
  1367.     refclock_receive(pst->peer, &off[i], delay, &pst->reftimes[NPSTSAMPS-1],
  1368.         &pst->rectimes[NPSTSAMPS-1], (pst->dontsync == 0));
  1369.  
  1370.     /*
  1371.      * If the don't-sync flag isn't on, we're nominal.
  1372.      */
  1373.     if (pst->dontsync == 0)
  1374.         pst_event(pst, CEVNT_NOMINAL);
  1375.     pst_reset(pst);
  1376. }
  1377.  
  1378.  
  1379.  
  1380. /*
  1381.  * pst_receive - receive data from a PST clock, call the appropriate
  1382.  *         routine to process it, and advance the state.
  1383.  */
  1384. void
  1385. pst_receive(rbufp)
  1386.     struct recvbuf *rbufp;
  1387. {
  1388.     register struct pstunit *pst;
  1389.     register u_long tmp;
  1390.     void pst_process();
  1391.  
  1392.     pst = (struct pstunit *)rbufp->recv_srcclock;
  1393.  
  1394.     /*
  1395.      * Process based on the current state.
  1396.      */
  1397.     switch(pst->state) {
  1398.     case STATE_IDLE:
  1399.         return;            /* Ignore the input */
  1400.  
  1401.     case STATE_QV:
  1402.         if (!pst_QV_process(pst, rbufp)) {
  1403.             /*
  1404.              * Set the state to idle, but request another
  1405.              * QV poll.
  1406.              */
  1407.             pst->badformat++;
  1408.             pst_event(pst, CEVNT_BADREPLY);
  1409.             pst->state = STATE_IDLE;
  1410.             pst->flags |= PST_DOQV;
  1411.         } else {
  1412.             /*
  1413.              * This went okay.  Advance the state to
  1414.              * QM and send the request.
  1415.              */
  1416.             pst->state = STATE_QM;
  1417.             pst_send(pst, "QM", 2);
  1418.         }
  1419.         return;
  1420.  
  1421.     case STATE_QM:
  1422.         if (!pst_QM_process(pst, rbufp)) {
  1423.             /*
  1424.              * Idle us and note the error
  1425.              */
  1426.             pst->badformat++;
  1427.             pst_event(pst, CEVNT_BADREPLY);
  1428.             pst->state = STATE_IDLE;
  1429.             return;
  1430.         }
  1431.         if (pst->flags & PST_NOTIME) {
  1432.             /*
  1433.              * Here we aren't getting any time because the
  1434.              * clock is still searching.  Don't bother
  1435.              * looking for anything.  Remove any leap
  1436.              * second hold, however, since this should
  1437.              * ensure the clock is sensible.
  1438.              */
  1439.             pst_event(pst, CEVNT_FAULT);
  1440.             pst->state = STATE_IDLE;
  1441.             pst->leapend = 0;
  1442.             if (pst->nextsample > 0)
  1443.                 pst_reset(pst);        /* Make sure rate low */
  1444.             return;
  1445.         }
  1446.  
  1447.         /*
  1448.          * Next is QD.  Do it.
  1449.          */
  1450.         pst->state = STATE_QD;
  1451.         pst_send(pst, "QD", 2);
  1452.         return;
  1453.  
  1454.     case STATE_QD:
  1455.         if (!pst_QD_process(pst, rbufp)) {
  1456.             /*
  1457.              * Idle us and note the error
  1458.              */
  1459.             pst->badformat++;
  1460.             pst_event(pst, CEVNT_BADDATE);
  1461.             pst->state = STATE_IDLE;
  1462.         } else {
  1463.             /*
  1464.              * Last step is QT.
  1465.              */
  1466.             pst->state = STATE_QT;
  1467.             pst_send(pst, "QT", 2);
  1468.         }
  1469.         return;
  1470.  
  1471.     case STATE_QT:
  1472.         pst->state = STATE_IDLE;
  1473.         if (!pst_QT_process(pst, rbufp, &pst->lastref, &pst->lastrec)) {
  1474.             /*
  1475.              * Note the error
  1476.              */
  1477.             pst->baddata++;
  1478.             pst_event(pst, CEVNT_BADTIME);
  1479.             return;
  1480.         }
  1481.         break;
  1482.  
  1483.     default:
  1484.         syslog(LOG_ERR,
  1485.     "pst clock: INTERNAL ERROR invalid state %d, unit %d, in receive",
  1486.             pst->state, pst->unit);
  1487.         return;
  1488.     }
  1489.  
  1490.  
  1491.     /*
  1492.      * You may not have noticed this, but the only way we end up
  1493.      * out here is if we've completed polling and have a couple of
  1494.      * valid time stamps.  First see if we should reset the
  1495.      * structure.
  1496.      */
  1497.     if (pst->nextsample > 0) {
  1498.         tmp = pst->lastrec.l_ui - pst->rectimes[0].l_ui;
  1499.         if (tmp > (u_long)psttab[pst->nextsample].tooold)
  1500.             pst_reset(pst);
  1501.     }
  1502.  
  1503.     pst->rectimes[pst->nextsample] = pst->lastrec;
  1504.     pst->reftimes[pst->nextsample] = pst->lastref;
  1505.     pst->nextsample++;
  1506.     if (pst->flags & PST_WWVH)
  1507.         pst->station--;
  1508.     else
  1509.         pst->station++;
  1510.  
  1511.     if (pst->flags & (PST_SIGFAULT|PST_HARDERR)) {
  1512.         pst_event(pst, CEVNT_FAULT);
  1513.         pst->dontsync++;
  1514.     } else if (pst->timesincesync > freerun[pst->unit]) {
  1515.         pst_event(pst, CEVNT_PROP);
  1516.         pst->dontsync++;
  1517.     } else if (pst->leapend > current_time) {
  1518.         pst->dontsync++;
  1519.     }
  1520.  
  1521.     if (pst->nextsample >= NPSTSAMPS)
  1522.         pst_process(pst);
  1523. }
  1524.  
  1525.  
  1526. /*
  1527.  * pst_leap - called when a leap second occurs
  1528.  */
  1529. void
  1530. pst_leap()
  1531. {
  1532.     register int i;
  1533.  
  1534.     /*
  1535.      * This routine should be entered a few seconds after
  1536.      * midnight UTC when a leap second occurs.  To ensure we
  1537.      * don't get foolish time from the clock(s) we reset it
  1538.      * (them).  We also set a 3 hour hold on each clock in
  1539.      * case the reset doesn't take, though this will be canceled
  1540.      * if the reset succeeds.
  1541.      */
  1542.     for (i = 0; i < MAXUNITS; i++) {
  1543.         if (unitinuse[i]) {
  1544.             pstunits[i]->leapend = current_time + PSTLEAPHOLD;
  1545.             pstunits[i]->flags |= PST_DORESET;
  1546.         }
  1547.     }
  1548. }
  1549.  
  1550.  
  1551. /*
  1552.  * pst_compute_delay - compute appropriate things to tell clock about delays
  1553.  */
  1554. void
  1555. pst_compute_delay(prop_delay, prop_data)
  1556.     u_long prop_delay;
  1557.     struct pst_propagate *prop_data;
  1558. {
  1559.     register int code;
  1560.     register u_long tsf;
  1561.     extern int tsftomsu();
  1562.  
  1563.     /*
  1564.      * Convert (truncate) the delay to milliseconds.  Save the
  1565.      * characters needed to send this to the clock and compute
  1566.      * the remainder to be added in later.
  1567.      */
  1568.     code = tsftomsu(prop_delay, 0);
  1569.     MSUTOTSF(code, tsf);
  1570.     prop_data->remainder = prop_delay - tsf;
  1571.     if (prop_data->remainder & 0x80000000)
  1572.         prop_data->remainder = 0;
  1573.     prop_data->msbchar = BINTOPST((code >> 2) & 0x1f);
  1574.     prop_data->lsbchar = BINTOPST(code & 0x3);
  1575. }
  1576.  
  1577.  
  1578. /*
  1579.  * pst_control - set fudge factors, return statistics
  1580.  */
  1581. void
  1582. pst_control(unit, in, out)
  1583.     u_int unit;
  1584.     struct refclockstat *in;
  1585.     struct refclockstat *out;
  1586. {
  1587.     register struct pstunit *pst;
  1588.     void pst_compute_delay();
  1589.  
  1590.     if (unit >= MAXUNITS) {
  1591.         syslog(LOG_ERR, "pst clock: unit %d invalid (max %d)",
  1592.             unit, MAXUNITS-1);
  1593.         return;
  1594.     }
  1595.  
  1596.     if (in != 0) {
  1597.         int doqv = 0;
  1598.  
  1599.         if (in->haveflags & CLK_HAVETIME1)
  1600.             if (in->fudgetime1.l_ui == 0
  1601.                 && in->fudgetime1.l_uf <= PSTMAXPROP) {
  1602.                 wwv_prop_delay[unit] = in->fudgetime1;
  1603.                 doqv = 1;
  1604.                 pst_compute_delay(wwv_prop_delay[unit].l_uf,
  1605.                     &wwv_prop_data[unit]);
  1606.             }
  1607.         if (in->haveflags & CLK_HAVETIME2)
  1608.             if (in->fudgetime2.l_ui == 0
  1609.                 && in->fudgetime2.l_uf <= PSTMAXPROP) {
  1610.                 wwvh_prop_delay[unit] = in->fudgetime2;
  1611.                 doqv = 1;
  1612.                 pst_compute_delay(wwvh_prop_delay[unit].l_uf,
  1613.                     &wwvh_prop_data[unit]);
  1614.             }
  1615.         if (in->haveflags & CLK_HAVEVAL1) {
  1616.             stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
  1617.         }
  1618.         if (in->haveflags & CLK_HAVEVAL2) {
  1619.             if (in->fudgeval2 > 0 && in->fudgeval2 < 9990)
  1620.                 freerun[unit] = (u_short)in->fudgeval2;
  1621.         }
  1622.         if (in->haveflags & CLK_HAVEFLAG1) {
  1623.             sloppyclock[unit] = in->flags & CLK_FLAG1;
  1624.         }
  1625.         if (unitinuse[unit]) {
  1626.             /*
  1627.              * Should actually reselect clock, but
  1628.              * will wait for the next timecode
  1629.              */
  1630.             if (in->haveflags & CLK_HAVEVAL1) {
  1631.                 pstunits[unit]->peer->stratum
  1632.                     = stratumtouse[unit];
  1633.                 if (stratumtouse[unit] > 1)
  1634.                     pstunits[unit]->peer->refid
  1635.                         = htonl(PSTHSREFID);
  1636.             }
  1637.  
  1638.             if ((in->haveflags & CLK_HAVEFLAG3) &&
  1639.                 (in->flags & CLK_FLAG3)) {
  1640.                 pstunits[unit]->flags |= PST_DORESET;
  1641.             } else if (doqv || ((in->haveflags & CLK_HAVEFLAG2) &&
  1642.                 (in->flags & CLK_FLAG2))) {
  1643.                 pstunits[unit]->flags |= PST_DOQV;
  1644.             }
  1645.         }
  1646.     }
  1647.  
  1648.     if (out != 0) {
  1649.         out->type = REFCLK_WWV_PST;
  1650.         out->flags = 0;
  1651.         out->haveflags
  1652.             = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
  1653.               CLK_HAVEVAL2|CLK_HAVEFLAG1;
  1654.         out->fudgetime1 = wwv_prop_delay[unit];
  1655.         out->fudgetime2 = wwvh_prop_delay[unit];
  1656.         out->fudgeval1 = (long)stratumtouse[unit];
  1657.         out->fudgeval2 = (long)freerun[unit];
  1658.         out->flags = sloppyclock[unit];
  1659.         if (unitinuse[unit]) {
  1660.             pst = pstunits[unit];
  1661.             out->clockdesc = pst->description;
  1662.             out->lencode = pst->lencode;
  1663.             out->lastcode = pst->lastcode;
  1664.             out->timereset = current_time - pst->timestarted;
  1665.             out->polls = pst->polls;
  1666.             out->noresponse = pst->noreply;
  1667.             out->badformat = pst->badformat;
  1668.             out->baddata = pst->baddata;
  1669.             out->lastevent = pst->lastevent;
  1670.             out->currentstatus = pst->status;
  1671.         } else {
  1672.             out->clockdesc = pstdefdesc;
  1673.             out->lencode = 0;
  1674.             out->lastcode = "";
  1675.             out->polls = out->noresponse = 0;
  1676.             out->badformat = out->baddata = 0;
  1677.             out->timereset = 0;
  1678.             out->currentstatus = out->lastevent = CEVNT_NOMINAL;
  1679.         }
  1680.     }
  1681. }
  1682.  
  1683.  
  1684. /*
  1685.  * pst_buginfo - return clock dependent debugging info
  1686.  */
  1687. void
  1688. pst_buginfo(unit, bug)
  1689.     int unit;
  1690.     register struct refclockbug *bug;
  1691. {
  1692.     register struct pstunit *pst;
  1693.     register int i;
  1694.  
  1695.     bug->nvalues = bug->ntimes = 0;
  1696.  
  1697.     if (unit >= MAXUNITS) {
  1698.         syslog(LOG_ERR, "pst clock: unit %d invalid (max %d)",
  1699.             unit, MAXUNITS-1);
  1700.         return;
  1701.     }
  1702.  
  1703.     if (!unitinuse[unit])
  1704.         return;
  1705.     pst = pstunits[unit];
  1706.  
  1707.     bug->nvalues = 14;
  1708.     bug->svalues = (1<<10);
  1709.     bug->values[0] = (u_long)pst->nextsample;
  1710.     bug->values[1] = (u_long)pst->state;
  1711.     bug->values[2] = (u_long)pst->reason;
  1712.     bug->values[3] = (u_long)pst->flags;
  1713.     bug->values[4] = (u_long)pst->yearday;
  1714.     bug->values[5] = (u_long)pst->hour;
  1715.     bug->values[6] = (u_long)pst->minute;
  1716.     bug->values[7] = (u_long)pst->second;
  1717.     bug->values[8] = (u_long)pst->millisecond;
  1718.     bug->values[9] = (u_long)pst->timezone;
  1719.     bug->values[10] = (u_long)((long)pst->tzoffset);
  1720.     bug->values[11] = (u_long)pst->timesincesync;
  1721.     bug->values[12] = pst->yearstart;
  1722.     if (pst->leapend > current_time)
  1723.         bug->values[13] = pst->leapend - current_time;
  1724.     else
  1725.         bug->values[13] = 0;
  1726.  
  1727.     bug->ntimes = ((NPSTSAMPS*2)+2) > NCLKBUGTIMES ? NCLKBUGTIMES :
  1728.         ((NPSTSAMPS*2)+2);
  1729.     bug->stimes = 0;
  1730.     for (i = 0; i < (bug->ntimes-2)/2; i++) {
  1731.         bug->times[2*i] = pst->rectimes[i];
  1732.         bug->times[(2*i) + 1] = pst->reftimes[i];
  1733.     }
  1734.     bug->times[bug->ntimes - 2] = pst->lastrec;
  1735.     bug->times[bug->ntimes - 1] = pst->lastref;
  1736. }
  1737. #endif
  1738.